#ifndef xpack_lang_cxx_parse_utc_date
#define xpack_lang_cxx_parse_utc_date
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::lang_cxx::inc
#include"chrono/datetime.hpp"
#include"define/base_type.hpp"
#include"lang/cxx/private/lut.utc_time.hpp"
#include"lang/cxx/private/parse_xxx_result.hpp"
#include"lang/cxx/index_of_prefix.hpp"
#include"lang/cxx/parse.hpp"
#include"lang/cxx/trim_start.hpp"
#include"lang/cxx.hpp"
#include"macro/xexport.hpp"
#pragma pop_macro("xuser")

namespace mixc::lang_cxx{
    template<class item_t>
    inline parse_utc_date_result parse_utc_date_core(auto const & self, utc_date_t const & lut){
        using result_t          = parse_utc_date_result;

        constexpr
        auto ok                 = uxx{};

        // Fri, 20 May 2022 05:20:00 GMT
        auto year               = 0;
        auto i_month            = 0;
        auto day                = 0;
        auto hour               = 0;
        auto minute             = 0;
        auto second             = 0;
        auto match              = self;
        auto i_week             = 0;
        auto i_dummy            = 0;
        auto i_miss             = uxx{};
        auto skip               = uxx{};

        auto skip_empty         = [&](auto trim_char = ' '){
            if (skip = (item_t *)match.trim_start(trim_char) - (item_t *)match; skip == 0){
                return not_exist;
            }
            else{
                match           = match.backward(skip);
                i_miss         += skip;
                return ok;
            }
        };

        auto fetch_i_str        = [&](int * value, auto && list, char prefix_char = '\0'){
            if (prefix_char == '\0'){
                ; // skip
            }
            else if (auto index = skip_empty(prefix_char); index == not_exist){
                return not_exist;
            }

            if (auto index = match.index_of_prefix(list); index == not_exist){
                return not_exist;
            }
            else{
                skip            = list[index]->length;
                *value          = index;
                i_miss         += skip;
                match           = match.backward(skip);
                return ok;
            }
        };

        auto fetch_value        = [&](int * value, char prefix_char = '\0'){
            if (prefix_char == '\0'){
                ; // skip
            }
            else if (auto index = skip_empty(prefix_char); index == not_exist){
                return not_exist;
            }

            auto parse_result   = match.template parse<i32>(); 
            skip                = parse_result->index_of_error;

            if (skip == 0){
                return not_exist;
            }
            else{
                match           = match.backward(skip);
                i_miss         += skip;
                *value          = parse_result;
                return ok;
            }
        };

        // Fri, 20 May 2022 05:20:00 GMT
        // ^^^
        if (fetch_i_str(& i_week, lut.weekday) == not_exist){
            return result_t{}->index_of_error(i_miss);;
        }

        // Fri, 20 May 2022 05:20:00 GMT
        //    ^
        if (match[0] != ','){
            return result_t{}->index_of_error(i_miss);;
        }
        else{
            match               = match.backward(1);
            i_miss             += 1;
        }

        // Fri, 20 May 2022 05:20:00 GMT
        //     ^^^
        if (fetch_value(& day, ' ') == not_exist){
            return result_t{}->index_of_error(i_miss);;
        }

        if (fetch_i_str(& i_month, lut.month, ' ') == not_exist){
            return result_t{}->index_of_error(i_miss);;
        }

        if (fetch_value(& year, ' ') == not_exist){
            return result_t{}->index_of_error(i_miss);;
        }

        if (fetch_value(& hour, ' ') == not_exist){
            return result_t{}->index_of_error(i_miss);;
        }

        if (fetch_value(& minute, ':') == not_exist){
            return result_t{}->index_of_error(i_miss);;
        }

        if (fetch_value(& second, ':') == not_exist){
            return result_t{}->index_of_error(i_miss);;
        }

        inc::datetime datetime(year, i_month + 1, day, hour, minute, second);
        inc::c08 gmt[] = { "GMT" }; 

        if (fetch_i_str(& i_dummy, gmt, ' ') == not_exist){
            return result_t { datetime, i_miss };
        }
        else if (match->length == zero){
            return result_t{ datetime };
        }
        else{
            return result_t{ datetime, i_miss };
        }
    }

    template<class item_t>
    inline parse_utc_date_result cxx<item_t>::parse_utc_date() const {
        return parse_utc_date_core<item_t>(xthe, make_utc_date);
    }
}

#endif
